/*
 Copyright (C) 2010-2013. 
 Ezequiel Palumbo, Calipsoide FOSS Foundation.
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public License
 along with this program.  If not, see http://www.gnu.org/licenses/. 
 
 Email: contacto@ehpalumbo.com.ar 
*/

package org.calipsoide.dbf2xml;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.calipsoide.dbf2xml.dbf.DBFDataExtractor;
import org.calipsoide.dbf2xml.dbf.TableDataExtractor;
import org.calipsoide.dbf2xml.model.Record;
import org.calipsoide.dbf2xml.xml.BasicDOMBuilder;
import org.calipsoide.dbf2xml.xml.DOMBuilder;
import org.calipsoide.dbf2xml.xml.XMLWriter;
import org.w3c.dom.Document;

/**
 * 
 * Facade that unifies API components for a simplified use of the 
 * functionality. It is intended to be created and used for each access.
 * 
 * @since 1.0
 * @author ehpalumbo
 *
 */
public class FileTableProcessor {

	private static final Log LOGGER = 
			LogFactory.getLog(FileTableProcessor.class);
	
	private final TableProcessingConfiguration configuration;
	private TableDataExtractor dataExtractor;
	private DOMBuilder domBuilder;

	/**
	 * 
	 * Creates a processor with the specified settings. 
	 * 
	 * @param configuration with settings for processing
	 * @throws FileNotFoundException if path references an unavailable location
	 * @throws IOException if extraction component fails on initialization 
	 * @see org.calipsoide.dbf2xml.TableProcessingConfiguration
	 * 
	 */
	public FileTableProcessor(
			final TableProcessingConfiguration configuration) 
			throws FileNotFoundException, IOException {
		super();
		this.configuration = configuration;
		init();
	}
	
	public Log getLogger() {
		return LOGGER;
	}

	public TableProcessingConfiguration getConfiguration() {
		return configuration;
	}

	public TableDataExtractor getDataExtractor() {
		return dataExtractor;
	}

	public DOMBuilder getDomBuilder() {
		return domBuilder;
	}

	private void init() throws FileNotFoundException, IOException {
		final FileInputStream inputStream = 
				new FileInputStream(getConfiguration().getPath());
		this.dataExtractor = new DBFDataExtractor(inputStream);
		this.domBuilder = new BasicDOMBuilder(); 
	}
	
	/**
	 * 
	 * Using the settings contained in the configuration, extracts data and 
	 * writes it over the OutputStream. 
	 * 
	 * @param outputStream to write XML over.
	 * @throws IOException if extraction or export fails during IO operations.
	 * 
	 */
	public void writeRecords(
			final OutputStream outputStream) 
			throws IOException {
		final TableProcessingConfiguration config = getConfiguration();
		final List<Record> records = getDataExtractor()
				.from(config.getSince())
				.limitTo(config.getMaximum())
				.project(config.getProjections())
				.restrict(config.getRestrictions())
				.extract();
		try {
			final DocumentBuilder documentBuilder = 
					DocumentBuilderFactory.newInstance().newDocumentBuilder();
			final Document document = documentBuilder.newDocument();
			getDomBuilder().build(document, records);
			new XMLWriter(config.getEncoding(), config.getIndent())
					.write(document, outputStream);
		} catch (ParserConfigurationException e) {
			getLogger().error("Error trying to create document.", e);
			throw new IllegalStateException(
					"Inconsistent document was generated, " +
					"discarding and aborting.", e);
		}
	}
	
}
